package cheesymock;

import java.lang.reflect.*;

public abstract class Mock {
	private Class<?> interfaceToImplement;
	private Validator[] validators;
	private Object delegate;
	private DefaultReturn defaultReturn;

	public Mock(Class<?> interfaceToImplement, Validator[] validators, Object delegate, 
			DefaultReturn defaultReturn) {
		for(Validator v: validators) {
		    v.creation(interfaceToImplement, delegate);
		}
		this.interfaceToImplement = interfaceToImplement;
		this.validators = validators;
		this.delegate = delegate;
		this.defaultReturn = defaultReturn;
	}

	protected Object doInvoke(Object proxy, Method method, Object[] arguments) throws Throwable {
		if ("equals".equals(method.getName())) {
		    return proxy == arguments[0];
		}
		for(Validator v: validators) {
		    v.invocation(method, arguments);
		}
		if (delegate != null) {
			try {
				Method m = MethodUtil.resolveMethod(method, arguments, delegate);
				m.setAccessible(true);
				return m.invoke(delegate, arguments);
			}
			catch (NoSuchMethodException nse) {
			}
			try {
				Field f = MethodUtil.resolveProperty(method, arguments, delegate);
				if (MethodUtil.isGetter(method, arguments)) {
					return f.get(delegate);
				}
				else {
					f.set(delegate, arguments[0]);
					return null;
				}
			}
			catch (NoSuchFieldException nsfe) {
			}
		}
		if (defaultReturn != null) {
		    return defaultReturn.value(method);
		}
		return null;
	}
    
	public void check() {
		for(Validator v: validators) {
			try {
				v.check();
			}
			catch (RuntimeException e) {
				Throwable t = e.getCause();
				if (t instanceof RuntimeException) {
				    throw (RuntimeException) t;
				}
				throw e;
			}
		}
	}
}